package com.appbee.core.client.rpcfilter.filters;

import java.util.Set;

import com.appbee.core.client.rpcfilter.RpcFilter;
import com.appbee.core.client.rpcfilter.RpcFilterChain;
import com.appbee.core.client.rpcfilter.callback.FilterCallback;
import com.google.web.bindery.requestfactory.shared.ServerFailure;
import com.google.web.bindery.requestfactory.shared.Violation;

public class MonoSyncFilter<I, R> implements RpcFilter<I, R>
{
	private boolean fetching = false;

	private I pendingRequest;

	private FilterCallback<R> currentCallback;

	private RpcFilterChain<I, R> currentChain;

	@Override
	public void doFilter(I input, FilterCallback<R> callback, RpcFilterChain<I, R> chain)
	{
		currentChain = chain;
		if (fetching)
		{
			pendingRequest = input;
			currentCallback = callback;
			return;
		}
		doFetch(input, callback);
	}

	private void doFetch(I input, final FilterCallback<R> callback)
	{
		fetching = true;
		currentChain.doFilter(input, new FilterCallback<R>()
		{
			@Override
			public void onSuccess(R result)
			{
				fetching = false;
				callback.onSuccess(result);
				checkPendingRequest();
			}

			@Override
			public void onFailure(ServerFailure error)
			{
				fetching = false;
				callback.onFailure(error);
				checkPendingRequest();

			}

			@Override
			public void onViolation(Set<Violation> errors)
			{
				fetching = false;
				callback.onViolation(errors);
				checkPendingRequest();
			}

			@Override
			public void onCancel(RpcFilter<?, R> layer)
			{
				fetching = false;
				callback.onCancel(layer);
				checkPendingRequest();
			}

		});
	}

	private void checkPendingRequest()
	{
		if (pendingRequest != null)
		{
			I request = pendingRequest;
			FilterCallback<R> cb = currentCallback;
			pendingRequest = null;
			currentCallback = null;
			doFetch(request, cb);
		}
	}

}
